#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>

static char gpio_path[100];

static int gpio_config(const char *attr, const char *val)
{
    char file_path[100];
    int len;
    int fd;

    sprintf(file_path, "%s/%s", gpio_path, attr);

    /*  打开路径    */
    fd = open(file_path, O_WRONLY);
    if(fd < 0) {
        perror("open error");
        return fd;
    }

    len = strlen(val);
    /*  写入val值   */
    if(len != write(fd, val, len)) {
        perror("write error");
        return -1;
    }
    close(fd);
    return 0;
}

/*  主函数    */
int main(int argc, char* argv[]) 
{
    struct pollfd pfd;
    char file_path[100];
    int ret;
    char val;

    /*校验传参*/
    if(2 != argc) {
        fprintf(stderr, "usage:%s<gpio>\n", argv[0]);
        exit(-1);
    }

    /*判断指定编号到GPIO是否导出*/
    sprintf(gpio_path,"/sys/class/gpio%s",argv[1]);

    if(access(gpio_path,F_OK)){
        int len;
        int fd;
        /*  常识打开路径文件    */
        fd = open("/sys/class/gpio/export",O_WRONLY);
        if(fd < 0){
            perror("open error");
            exit(-1);
        }

        len = strlen(argv[1]);
        if(len != write(fd,argv[1],len)){
            perror("write error");
            exit(-1);
        }

        close(fd);
    }

    /*配置输出模式*/
    if (gpio_config("direction", "in"))
        exit(-1);

    /*极性设置*/
    if (gpio_config("active_low", "0"))
        exit(-1);

    /* 配置中断触发方式: 上升沿和下降沿 */
    if (gpio_config("edge", "both"))
        exit(-1);

    /* 打开 value 属性文件 */
    sprintf(file_path, "%s/%s", gpio_path, "value");
    if (0 > (pfd.fd = open(file_path, O_RDONLY))){
        perror("open error");
        exit(-1);
    }

    /*调用 poll*/
    pfd.events = POLLPRI; //只关心高优先级数据可读（中断）

    read(pfd.fd, &val, 1);//先读取一次清除状态

    for ( ; ; )
    {
        ret = poll(&pfd, 1, -1); //调用 poll
        if (0 > ret) {
            perror("poll error");
            exit(-1);
        }
        else if (0 == ret){
            fprintf(stderr,"poll timeout.\n");
            continue;
        }
        
        /*校验高优先级数据是否可读*/
        if(pfd.revents & POLLPRI) {
            if (0 > lseek(pfd.fd, 0, SEEK_SET)) {//将读位置移动到头部
                perror("lseek error");
                exit(-1);
            }

            if (0 > read(pfd.fd, &val, 1)) {
                perror("read error");
                exit(-1);
            }

            printf("GPIO 中断触发<value=%c>\n", val);
        
        }
    }

    /*  退出程序  */
    exit(0);
}